/*
    *@brief				:与select()函数很相似

    *@param[fds]	    :指向一个 struct pollfd 类型的数组，数组中的每个元素都会指定一个文件描述符以及我们对该文件描述符所关心的条件，稍后介绍 struct pollfd 结构体类型
    *@param[timeout]    : nfds 指定了 fds 数组中的元素个数，数据类型 nfds_t 实际为无符号整形。
    *@param[timeout]    :与 select()函数的 timeout 参数相似，用于决定 poll()函数的阻塞行为，具体用法如下：
                        -如果 timeout 等于-1，则 poll()会一直阻塞（与 select()函数的 timeout 等于 NULL 相同），直到 fds数组中列出的文件描述符有一个达到就绪态或者捕获到一个信号时返回。
                        -如果 timeout 等于 0， poll()不会阻塞，只是执行一次检查看看哪个文件描述符处于就绪态。
                        -如果 timeout 大于 0，则表示设置 poll()函数阻塞时间的上限值，意味着 poll()函数最多阻塞 timeout毫秒，直到 fds 数组中列出的文件描述符有一个达到就绪态或者捕获到一个信号为止。

    *@return 			:返回-1 表示有错误发生，并且会设置 errno。
                        -返回 0 表示该调用在任意一个文件描述符成为就绪态之前就超时了。
                        -返回一个正整数表示有一个或多个文件描述符处于就绪态了， 返回值表示 fds 数组中返回的 revents变量不为 0 的 struct pollfd 对象的数量。
*/

/*
    int poll(struct pollfd *fds, nfds_t nfds, int timeout);
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>

#define MOUSE "/dev/input/event2"

int main(void)
{
    char buf[100];
    int fd, ret = 0, flag;
    fd_set rdfds;
    int loops = 5;
    struct pollfd fds[2];

    /* 打开鼠标设备文件 */
    fd = open(MOUSE, O_RDONLY | O_NONBLOCK);
    if (-1 == fd)
    {
        perror("open error");
        exit(-1);
    }

    /* 将键盘设置为非阻塞方式 */
    flag = fcntl(0, F_GETFL); //先获取原来的 flag
    flag |= O_NONBLOCK;       //将 O_NONBLOCK 标准添加到 flag
    fcntl(0, F_SETFL, flag);  //重新设置 flag

    /* 同时读取键盘和鼠标 */
    fds[0].fd = 0;
    fds[0].events = POLLIN; //只关心数据可读
    fds[0].revents = 0;

    fds[1].fd = fd;
    fds[1].events = POLLIN; //只关心数据可读
    fds[1].revents = 0;

    /* 同时读取键盘和鼠标 */
    while (loops--)
    {
        ret = poll(fds, 2, -1);
        if (0 > ret)
        {
            perror("select error");
            goto out;
        }

        else if (0 == ret)
        {
            fprintf(stderr, "select timeout.\n");
            continue;
        }

        /* 检查键盘是否为就绪态 */
        if (fds[0].revents & POLLIN)
        {
            ret = read(0, buf, sizeof(buf));
            if (0 < ret)
                printf("键盘: 成功读取<%d>个字节数据\n", ret);
        }

        /* 检查鼠标是否为就绪态 */
        if (fds[1].revents & POLLIN)
        {
            ret = read(fd, buf, sizeof(buf));
            if (0 < ret)
                printf("鼠标: 成功读取<%d>个字节数据\n", ret);
        }
    }

out:
    /* 关闭文件 */
    close(fd);
    exit(ret);
}